/**
 * 暂不考虑gif
 */

import EXIF from "@nuofe/exif-js";
import { FILETYPE, IMAGEERROR } from "./errorType";
import {STATIC_TIMEOUT, STATIC_RESPONSE_ERROR, STATIC_FILE_ERROR, STATIC_COMPRESS_ERROR, STATIC_EXCHANGE_ERROR} from './statusEnum'
import createImage from "./image";
import Compress from "./compress";
import XHRUpload from "./upload";

const defaultSize = 2 * 1024 * 1024; // 默认大小2M

/**
 * 给Function 类型的变量赋默认值
 * @param {Function} func
 * @param {*} type
 */
function defaultValue(func, type) {
  return func || (() => undefined);
}

class Upload {
  constructor({
    fileType = /\/(?:jpeg|png|gif|jpg)/i,
    changeType = "image/jpeg",
    elem = null,
    base64 = null,
    maxSize = defaultSize,
    multiple = false,
    beforeUpload,
    uploading,
    successUpload,
    errorUpload,
    xhrParam,
    uploadUrl,
    uploadTimeout = 60,
    formdataName='file',
    fileName='blob'
  }) {
    this.elem = elem;
    this.maxSize = maxSize;
    this.base64 = base64;
    this.beforeUpload = beforeUpload;
    this.uploading = defaultValue(uploading);
    this.successUpload = defaultValue(successUpload);
    this.errorUpload = defaultValue(errorUpload);
    this.errorUpload = defaultValue(errorUpload);
    this.fileType = fileType;
    this.changeType = changeType;
    this.uploadUrl = uploadUrl;
    this.uploadTimeout = uploadTimeout;
    this.fileName = fileName;
    // 上传文件的 name
    this.formdataName = formdataName;
    // 上传的额外参数
    this.xhrParam = xhrParam;
    // 如果传入的是节点,需要调用init拿到将图片文件转为base64
    if (elem) {
      const fileList = elem.files;
      if (fileList && fileList.length) {
        const files = Array.prototype.slice.call(fileList);
        // TODO: 暂时支持单文件上传
        if (!multiple) {
          const file = files[0];
          if (
            this.beforeUpload &&
            this.beforeUpload({ file, type: "file", status: "getFile" }) ===
              false
          ) {
            // 用户传递了beforeUpload 如果返回false 直接中断
            return;
          } else {
            if (!fileType.test(file.type)) {
              this.errorUpload({
                message: '文件类型错误',
                errorType: FILETYPE,
                status: STATIC_FILE_ERROR
              });
              return false;
            }
          }
          this.init(file);
        }
      } else {
        this.errorUpload({
          message: '未获取到上传文件',
          errorType: FILETYPE,
          status: STATIC_FILE_ERROR
        });
      }
    } else if (this.base64) {
      // base64 图片无需获取方向信息，可直接执行压缩上传
      createImage(this.base64)
        .then(image => {
          // 将图片的类型统一转换 指定类型 默认 JPEG，
          this.changeImage(image);
        })
        .catch(error => {
          this.errorUpload({
            message: "创建base64文件失败",
            errorType: IMAGEERROR,
            status: STATIC_EXCHANGE_ERROR
          });
        });
    }
  }

  init(imgFile) {
    const _that = this;
    // 获取照片方向角属性，用户旋转控制
    EXIF.getData(imgFile, function() {
      const Orientation = EXIF.getTag(this, "Orientation");
      _that.Orientation = Orientation;
      _that.getFileResult(imgFile);
    });
  }

  getFileResult(imgFile) {
    const reader = new FileReader();
    reader.readAsDataURL(imgFile);
    reader.onload = eventFile => {
      const { result } = eventFile.target;
      createImage(result)
        .then(image => {
          // 将图片的类型统一转换 指定类型 默认 JPEG，
          this.changeImage(image);
        })
        .catch(error => {
          this.errorUpload({
            message: "blob转换错误",
            errorType: IMAGEERROR,
            status: STATIC_EXCHANGE_ERROR
          });
        });
    };
  }

  changeImage(image) {
    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");
    const { width, height } = image;
    canvas.width = width;
    canvas.height = height;
    ctx.fillStyle = "#fff";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.drawImage(image, 0, 0, width, height);
    if (this.Orientation) {
      // 如果方向角不为1，都需要进行旋转
      switch (this.Orientation) {
        case 6: // 需要顺时针（向左）90度旋转
          canvas.width = height;
          canvas.height = width;
          ctx.rotate((1 * 90 * Math.PI) / 180);
          ctx.drawImage(image, 0, -height, width, height);
          break;
        case 8: // 需要逆时针（向右）90度旋转
          canvas.width = height;
          canvas.height = width;
          ctx.rotate((3 * 90 * Math.PI) / 180);
          ctx.drawImage(image, -width, 0, width, height);
          break;
        case 3: // 需要180度旋转
          ctx.rotate((2 * 90 * Math.PI) / 180);
          ctx.drawImage(image, -width, -height, width, height);
          break;
        default:
          ctx.drawImage(image, 0, 0, width, height);
          break;
      }
    }
    const nbase64 = canvas.toDataURL(this.changeType, 1);
    canvas.width = 0;
    canvas.height = 0;
    // 执行压缩
    Compress({
      base64: nbase64,
      maxSize: this.maxSize,
      fileType: this.changeType
    })
      .then(data => {
        // 压缩成功后对上传最后拦截
        if (data.result) {
          const { base64 } = data;
          if (
            this.beforeUpload &&
            this.beforeUpload({
              file: base64,
              type: "compress",
              status: 200
            }) === false
          ) {
            return;
          }
          this.startUpload(base64);
        }
      })
      .catch(error => {
        console.warn(error);
        this.errorUpload({
          message: "压缩失败",
          errorType: IMAGEERROR,
          status: STATIC_COMPRESS_ERROR
        });
      });
  }

  startUpload(base64) {
    const {
      changeType,
      beforeUpload,
      uploading,
      successUpload,
      errorUpload,
      xhrParam,
      uploadUrl,
      uploadTimeout,
      formdataName,
      fileName,
    } = this;
    XHRUpload({
      base64,
      changeType,
      beforeUpload,
      uploading,
      successUpload,
      errorUpload,
      xhrParam,
      uploadUrl,
      uploadTimeout,
      formdataName,
      fileName
    });
  }
}
/**
 * @description 单图片上传集中处理
 * @property {String} uploadUrl 上传文件地址，必传
 * @property {RegExp} fileType 文件类型正则， default: /\/(?:jpeg|png|gif|jpg)/
 * @property {Object} elem example:{files:[file]} 文件域节点 target
 * @property {String} base64 图片base64
 * @property {Number} maxSize 文件size最大限制, default:2 * 1024 * 1024; // 默认大小2M
 * @property {Boolean} multiple 是否多文件 default:false, PS: 不支持多文件
 * @property {Object} xhrParam 上传额外参数
 * @property {String} fileName 上传文件名称 用于new FormDate() append方法第三个参数, default:'blob'
 * @property {String} formdataName 上传文件 name, default:'file'
 * @property {Number} uploadTimeout 执行上传接口时间 单位：s, default:60
 * @property {Function} beforeUpload 上传前调用函数 返回 false 阻止上传
 * @property {Function} uploading 调用上传接口时触发
 * @property {Function} successUpload 调用上传接口成功调用，直接返回接口响应报文JSON格式
 * @property {Function} errorUpload 上传失败回调  {status,errorType, message} 
 * @return ========= 失败详解 =====
 * @type status 502 接口上传超时， 999 响应失败， 1000 上传文件异常， 1001 图片压缩异常， 1002 图片转换异常
 * @type errorType 
 * @typw message 
 */
function YbsUpload(...args) {
  return new Upload(...args);
}
export default YbsUpload;
